--[[
	Ikarus Unit-Frames Addon	
	released under GNU General Public License version 3 (GPLv3) 
	by McGaerty & Sl4ker
	
	contact: mcgaerty@ikarus-systems.net rom@sl4ker.de	
	download: http://rom.curse.com/downloads/rom-addons/details/ikarus-unitframes.aspx
	
	special thanks to Qwox and novayuna for inspiration and stable basics
]]



local ikarus = {};
_G["ikarus"] = ikarus;

--  Flags for load operations
ikarus.isInitialised = false;
ikarus.delegatesLoaded = false;
--  Maps unit names to delegates
ikarus.unitDelegates = {};
--  Maps events to unit name lists of handlers
ikarus.registeredEvents = {};
--  Provides access to some utility functions
ikarus.utils = {};
--  Provides access to the mob db
ikarus.mobdb = {};
--  Provides access to some interface functions
ikarus.ui = {};
--  Provides access to some debug functions
ikarus.debug = {};
--  Stores profile data
ikarus.profile = {};
--  Provides locales
ikarus.lang = {};
--  Holds some general constants
ikarus.constants = {};
--  Ikarus unit frame  code
ikarus.iuc = {};
--  Ikarus colorizer support
ikarus.colorizers = {};
--  Root of the config menu functions
ikarus.config = {};
ikarus.config.interface = {};
ikarus.config.isLoaded = false;

ikarus.config.defaults = {	
    ["VARIABLES_VERSION"] = "1.1",
    ["RESOLUTION"] = {x = 1280, y = 1024}
};
--  Saves stuff like color picker states, callback methods etc
ikarus.config.utilities = {};


SaveVariables("Ikarus_VARS");
--[[
     ***********************************************************************
    BEGIN IKARUS
     ***********************************************************************
]]
function ikarus:NewClass(baseClass)
    local newClassObject = {};
    local classMetaTable = { __index = newClassObject };

	--  Creates new instance of subclass
    function newClassObject:Create(...)
        local newInstance = {};
        setmetatable(newInstance, classMetaTable);
        if(newInstance.Init) then
            newInstance:Init(...);
        end;
		
        return newInstance;
    end;

    if(baseClass ~= nil) then
        setmetatable(newClassObject, { __index = baseClass });
    end

    -- Return the class object of the instance
    function newClassObject:GetClass()
        return newClassObject;
    end

    -- Return the super class object of the instance
    function newClassObject:SuperClass()
        return baseClass;
    end

    -- Return true if the caller is an instance of theClass
    function newClassObject:InstanceOf(aClass)
        local isInstanceOf = false;

        local currentClassObject = newClassObject;

        while (currentClassObject ~= nil) and (isInstanceOf == false) do
            if(currentClassObject == aClass) then
                isInstanceOf = true;
            else
                currentClassObject = currentClassObject:SuperClass();
            end
        end

        return isInstanceOf;
    end

    return newClassObject;
end;

--[[
     ***********************************************************************
    END IKARUS
     ***********************************************************************
]]



function ikarus:Initialise()
	self:InitialiseUnitDelegates();
	--self:LoadFile(self.constants["ADDON_DIR"] .. "profiles/default.lua");
	self:LoadUtilities();
	self.LoadProfileInformation();

    self.isInitialised = true;
	local msg = string.gsub(ikarus.lang.messages.LOADED, "$VERSION", self.utils:VersionString());
    self.utils:Print(msg);
end;

function ikarus:LoadConfigOnUnitDelegates()
    if (self.config.isLoaded) then
        self.unitDelegates.global:LoadConfig();
		self.delegatesLoaded = true;
    end;
end;

function ikarus:InitialiseUnitDelegates()
	self:LoadUnit("global");
	self:LoadUnit("player");
	self:LoadUnit("target");
	self:LoadUnit("targettarget");
	self:LoadUnit("targettargettarget");
	self:LoadUnit("party");
	self:LoadUnit("partytarget");
	self:LoadUnit("playercastbar");
	self:LoadUnit("targetcastbar");
end;

function ikarus:LoadFile(filename)
	local func, err = loadfile(filename);
	if (err) then
		return false, err;
	end;
	return true, func();
end;

function ikarus:LoadUnit(unit)
	local file = self.constants["ADDON_DIR"] .. "units/"..unit..".lua";
	local done, res = self:LoadFile(file);
    if not(done) then
		local msg = string.gsub("Failed to load unit file: $FILE", "$FILE", file);
		ikarus.utils:Print(msg, true);
	else
		if(res.SetEnabled) then
			res:SetEnabled(true);
		end;
		self.unitDelegates[unit] = res;
	end;
end;

--  Register the handler to receive the desired event
function ikarus:RegisterEvent(event, unit)
    if not (event and unit) then
        return;
    end;

    if(self.registeredEvents[event] == nil)then
        self.registeredEvents[event] = {};
        getglobal("Ikarus_EventFrame"):RegisterEvent(event);
    end

    for k, v in pairs(self.registeredEvents[event]) do
        if(v == unit)then
            return;
        end;
    end;

    table.insert(self.registeredEvents[event], unit);
end;

--  Remove the handler from the list of registered handlers
function ikarus:UnregisterEvent(event, unit)
    if not (event and unit) then
        return;
    end;
    if not (self.registeredEvents[event])then
        return;
    end;
    
    for k, v  in pairs(self.registeredEvents[event]) do
        if(v == unit)then
            table.remove(self.registeredEvents[event], k);
            
            if(self.registeredEvents[event][1] == nil)then
                getglobal("Ikarus_EventFrame"):UnregisterEvent(event);
            end;
        end;
    end;
end;

--  Forward the event to all registered handlers
function ikarus:OnEvent(event, ...)
    if(self.registeredEvents[event] ~= nil)then
        for _, v in pairs(self.registeredEvents[event]) do
            if(ikarus.unitDelegates[v].OnEvent)then
                ikarus.unitDelegates[v]:OnEvent(event, ...);
            end;
        end;
    end;
end;

function ikarus:OnScriptEvent(event, unit, ...)
    if(self.unitDelegates[unit] ~= nil)then
        if(type(self.unitDelegates[unit].OnScriptEvent) == "function")then
            self.unitDelegates[unit]:OnScriptEvent(event, ...);
        end;
    end;
end;

function ikarus:IsInitialised()
    if(self.isInitialised)then
        return true;
    else
        return false;
    end;
end;

function ikarus:GetDelegate(unit)
	return self.unitDelegates[string.lower(unit)];
end;

function ikarus:SetDummyState(enable)
	for unit, delegate in pairs(self.unitDelegates) do
		if(unit ~= "global") then
			delegate:SetDummy(enable);
			delegate:UpdateAll();
		end;
	end;
end;

function ikarus:SetDelegatesEnabled(enable)
	for unit, delegate in pairs(self.unitDelegates) do
		if(unit ~= "global") then
			delegate:SetEnabled(enable);
		end;
	end;
end;

function ikarus:UpdateDelegates()
	for unit, delegate in pairs(self.unitDelegates) do
		if(unit ~= "global") then
			delegate:UpdateAll();
		end;
	end;
end;

function ikarus:LoadProfileInformation()
	local playerName = UnitName("player");
    if not (Ikarus_VARS) then
        Ikarus_VARS = {};
    end;
    if not (Ikarus_VARS.PROFILES) then
        Ikarus_VARS.PROFILES = {};
    end;
	
    if not(Ikarus_VARS.PROFILES[playerName])then
        Ikarus_VARS.PROFILES[playerName] = playerName;
    end;
	
	ikarus:SetProfileName(Ikarus_VARS.PROFILES[playerName]);
end;

function ikarus:GetProfileName()
	return ikarus.profileName or UnitName("player");
end;

function ikarus:SetProfileName(name, noReload)
	--ikarus.debug:Print("set: "..name.." "..ikarus:GetProfileName().." "..tostring(noReload));
	if(ikarus.profileName ~= name and ikarus.utils:IsValidString(name)) then
		if(ikarus.profileName and ikarus:IsInitialised()) then
			ikarus.config:SaveProfile()
		end;
		ikarus.profileName = name;
        Ikarus_VARS.PROFILES[UnitName("player")] = name;
		ikarus.config:LoadProfile(name, noReload);
		return true;
	end;
end;

function ikarus.config:LoadProfile(name, noReload)
	
    if(Ikarus_VARS[name])then
		ikarus.profile = Ikarus_VARS[name];
        if(Ikarus_VARS[name].VARIABLES_VERSION ~= nil 
			and tonumber(self.defaults.VARIABLES_VERSION) > tonumber(Ikarus_VARS[name].VARIABLES_VERSION))then
			
			--  Load interface files if required	
			if not (ikarus.profileManager) then				
			    local file = tostring(ikarus.constants["ADDON_DIR"] .. "libs/ProfileManager.lua");
			    if not(ikarus:LoadFile(file)) then
					ikarus.utils:Print(string.gsub(ikarus.lang.messages.BAD_FILE, "$FILE", file));
				end;
				ikarus.profileManager:Initialise();
			end;
			
			--  Update profile to the latest version (may modify or delete several parts)
			
			ikarus.profileManager:UpdateProfile(
				tonumber(self.defaults.VARIABLES_VERSION), ikarus.profile, ikarus.profile.RESOLUTION);
        end;
    else
        Ikarus_VARS[name] = {};
        Ikarus_VARS[name] = self.defaults;
		ikarus.profile = Ikarus_VARS[name];
    end;
	
    --  DEBUG always load defaults
	--Ikarus_VARS[name] = self.defaults;
	--  END DEBUG
	
	
	ikarus.profile.global.GENERAL.PROFILE = name;
	
    self.isLoaded = true;
	if not(noReload) then
		ikarus:LoadConfigOnUnitDelegates();
	end;
end;

function ikarus.config:SaveProfile()
	--ikarus.debug:Print("saving: "..ikarus.profileName);
    Ikarus_VARS[ikarus.profileName] = ikarus.profile;
end;

function ikarus.config:IsLoaded()
    if(self.isLoaded)then
        return true;
    else
        return false;
    end;
end;

function ikarus.config:DropDownShow()
	--ikarus.debug:Print("showing dropdown");
	local info = {};	
	info.text = "Config";
	info.value = "CONFIG";
	info.func = ikarus.config.OnDropDownSelect;
	UIDropDownMenu_AddButton(info);
	
	info = {};
	info.text = "Profile Manager";
	info.value = "PROFILER";
	info.func = ikarus.config.OnDropDownSelect;
	UIDropDownMenu_AddButton(info);
end;

function ikarus.config.OnDropDownSelect(button)
	--ikarus.debug:Print(tostring(button.value));
	if(button.value == "CONFIG") then
		ikarus.config:ToggleConfigMenu();
	elseif(button.value == "PROFILER") then
		ikarus.config:ToggleProfileManager();
	end;
end;

function ikarus.config:ToggleConfigDropDown()
	ToggleDropDownMenu(Ikarus_MinimapButtonDropDown, 1, nil, "Ikarus_MinimapButton");
end;

function ikarus.config:ToggleProfileManager()
	--  Load interface files if required	
	if not (ikarus.profileManager) then				
	    local file = tostring(ikarus.constants["ADDON_DIR"] .. "libs/ProfileManager.lua");
	    if not(ikarus:LoadFile(file)) then
			ikarus.utils:Print(string.gsub(ikarus.lang.messages.BAD_FILE, "$FILE", file));
		end;
	end;

    if (ikarus.profileManager:IsVisible())then
		ikarus.profileManager:HideConfigFrame();
	else
		if(ikarus.config.menu) then
			ikarus.config.menu:HideConfigFrame();
		end;
			
        ikarus.profileManager:ShowConfigFrame();
    end;
end;

function ikarus.config:ToggleConfigMenu()
	--  Load interface files if required	
	if not (ikarus.config.menu) then				
	    local file = tostring(ikarus.constants["ADDON_DIR"] .. "libs/Menu.lua");
	    if not(ikarus:LoadFile(file)) then
			ikarus.utils:Print(string.gsub(ikarus.lang.messages.BAD_FILE, "$FILE", file));
		end;
	end;

    if (ikarus.config.menu:IsVisible())then
		ikarus.config.menu:HideConfigFrame();
	else
		if(ikarus.profileManager) then
			ikarus.profileManager:HideConfigFrame();
		end;
        ikarus.config.menu:ShowConfigFrame();
    end;
end;

function ikarus:LoadUtilities()
	ikarus.iuc:Initialise();
	ikarus.colorizers:Initialise();
	UIDropDownMenu_Initialize(Ikarus_MinimapButtonDropDown, ikarus.config.DropDownShow, "MENU");
end;

function ikarus:LoadLocales()
    local language = ikarus.profile.global.GENERAL.LANGUAGE or "ENEU";
	
	--ikarus.debug:Print(language);
		
    local file = tostring(self.constants["ADDON_DIR"] .. "lang/ikarus_lang_" .. language .. ".lua");
    if not(ikarus:LoadFile(file)) then
		ikarus.utils:Print("Failed to load language file: "..file, true);
	end;
end;


--[[
    ***********************************************************************
    MobDB functions
    ***********************************************************************
]]

function ikarus.mobdb:UpdateMobDB(target)
	--  If no pbInfo loaded, update own db
	if(pbInfo == nil) then
		if (UnitExists(target) and not UnitIsPlayer(target) and UnitLevel(target) > 0) then
			local name = UnitName(target);
			local mL, sL = UnitLevel(target);
			local healthMax = UnitChangeHealth(target);
			if (type(ikarus.mobdb[name]) ~= "table") then
				ikarus.mobdb[name] = {};
			end;
			if (type(ikarus.mobdb[name][mL]) ~= "table") then
				ikarus.mobdb[name][mL] = {};
			end;
			if (UnitHealth(target) == 100 and (ikarus.mobdb[name][mL]["healthpoints"] or 0) < healthMax) then
				ikarus.mobdb[name][mL]["healthpoints"] = healthMax;
			end;
		end;
	else
		--  v0.26
		--  we do not update, since pbInfo does this on mouseover
		--  well, now we do...
		pbInfo.MobDB.Update(target);
	end;
end;

function ikarus.mobdb:UnitMaxHealth(unit)
	local name, lvl = UnitName(unit), UnitLevel(unit);
	local db = ikarus.mobdb;
	if not(name and lvl and lvl > 0) then
		return 100;
	elseif(pbInfo) then
		--  v0.29
		db = pbInfo.MobDB.Mobs;
	end;
	
	if(db and db[name] and db[name][lvl] and db[name][lvl]["healthpoints"]) then
		return db[name][lvl]["healthpoints"];
	else
		return 100;
	end;
end;

function ikarus:OnUpdate(frame, elapsed)
	if(frame.delay and frame.delay > 0) then
		frame.delay = frame.delay - elapsed;
		if(frame.delay <= 0) then
			RunScript("SYS_DisplaySettings_Frame:Hide()");	
			RunScript("SYS_DisplaySettings_Frame:SetPos("..frame.configX..","..frame.configY..")");		
			frame.delay = nil;
		end;
	end;
end;


--[[
    ***********************************************************************
    Utility functions
    ***********************************************************************
]]

function ikarus.utils:Print(text, isError)
    if(isError)then
        DEFAULT_CHAT_FRAME:AddMessage(tostring(text), 1.0, 0.0, 0.0);
    else
        DEFAULT_CHAT_FRAME:AddMessage(tostring(text));
    end;
end;

function ikarus.utils:IsValidString(text)
    if(text ~= nil and string.len(tostring(text)) > 0) then
		return true;
	else
		return false;
	end;
end;

function ikarus.utils:IsValidName(text)
	return self:IsValidString(text);
end;

function ikarus.utils:UnitIsParty(unit)
    if(string.sub(unit, 1, 5) == "party")then
        return true;
    else
        return false;
    end;
end;

function ikarus.utils:FormatNumber(value, form)
	if(form == "SHORTENED" and value >= 999) then	
	   if(value < 999999)then
	        return string.format("%.1fk", value / 1000)
	    else
			return string.format("%.2fm", value / 1000000)
		end
	else
		return tostring(value);
	end;
end;

function ikarus.utils:VersionString()
	return ikarus.constants.VERSION_NUMBER .." ".. ikarus.constants.VERSION_SUFFIX;
end;

--  START pbInfo functions
--  Special thx to p.b. a.k.a. novayuna for this ;)
--  saved me a hell of a lot of time.
ikarus.utils.hex = {[10] = "A", [11] = "B", [12] = "C", [13] = "D", [14] = "E", [15] = "F"};
function ikarus.utils:makeHex(decimal)
	if(ikarus.utils.hex[decimal] ~= nil) then
		return ikarus.utils.hex[decimal];
	end;
	return tostring(decimal);
end;

ikarus.utils.conversion = {
	{"max", "+", "min"}, {"-", "max", "min"}, {"min", "max", "+"}, 
	{"min", "-", "max"}, {"+", "min", "max"}, {"max", "min", "-"}
};
function ikarus.utils:HSBtoRGB(hueVal, saturation, brightness)
	local hue = math.mod(math.abs(hueVal), 360);
	local index, minValue, maxValue, rgb = math.floor(hue / 60) + 1, (brightness / 100) * ((100 - saturation) / 100), brightness / 100, {};
	for color = 1, 3 do
		if (ikarus.utils.conversion[index][color] == "min") then
			rgb[color] = minValue;			
		elseif (ikarus.utils.conversion[index][color] == "max") then
			rgb[color] = maxValue;
		elseif (ikarus.utils.conversion[index][color] == "+") then
			rgb[color] = minValue + (math.mod(hue, 60) / 60) * (maxValue - minValue);
		else
			rgb[color] = maxValue - (math.mod(hue, 60) / 60) * (maxValue - minValue);
		end;
	end;
	return {r = rgb[1]; g = rgb[2]; b = rgb[3]};
end;

function ikarus.utils:RGBtoHEX(color)
	local rgb, hex = {color.r, color.g, color.b}, {};
	for i, v in ipairs(rgb) do
		v = math.ceil(((v > 1 and 1) or v) * 255);
		hex[i] = makeHex(v / 16 - (math.mod(v, 16) / 16)) .. makeHex(math.mod(v, 16));
	end;
	return table.concat(hex);
end;

function ikarus.utils:HSBtoHEX(hue, saturation, brightness)
	return RGBtoHEX(HSBtoRGB(hue, saturation, brightness));
end;
-- END pbInfo

function unpackCol(color)
	return color.r, color.g, color.b, color.a;
end;

function ikarus.utils:TableCopy(source, target) 
	if(source) then
		for k,v in pairs(source) do
			if(type(v) == "table") then
				target[k] = self:TableClone(v);
			else
				target[k] = v;	
			end;
		end;
	end;
end;

function ikarus.utils:TableClear(source) 
	if(source) then
		for k,v in pairs(source) do
			source[k] = nil;
		end;
	end;
end;

function ikarus.utils:TableClone(source) 
	if(source) then
		local target = {};
		self:TableCopy(source, target);
		return target;
	end;
end;


--[[
    ***********************************************************************
    Interface functions
    ***********************************************************************
]]

function ikarus.ui:SetAnchor(frame, parent, anchor, parentAnchor, x, y, scale)
	if(type(frame) ~= "table") then
		frame = getglobal(tostring(frame));
	end;
	if(type(parent) == "table") then
		parent = parent:GetName();
	end;
	if(scale == nil or not type(scale) == "number") then
		scale = 1.0;
	end;
	frame:ClearAllAnchors();
	--frame:SetAnchor(tostring(anchor), tostring(parentAnchor), parent, x * scale, y * scale);
	frame:SetAnchor(tostring(anchor), tostring(parentAnchor), parent, x, y);
end;

function ikarus.ui:SetAlignment(frame, parent, alignment, x, y, scale)
	local anchors = ikarus.constants.alignments[alignment];
	if(anchors ~= nil) then
		self:SetAnchor(frame, parent, anchors[1], anchors[2], x, y, scale);
	end;
end;

function ikarus.ui:SetInnerAlignment(frame, parent, alignment, x, y, scale)
	if(anchors ~= nil) then
		self:SetAnchor(frame, parent, alignment, alignment, x, y, scale);
	end;
end;

function ikarus.ui:SetFontSize(frame, size)
	if(type(frame) ~= "table") then
		frame = getglobal(tostring(frame));
	end;
	frame:SetFontSize(size);
	frame:SetText("");
end;

function ikarus.ui:Resize(frame, width, height, scale)
	if(width and height) then
		if(type(frame) ~= "table") then
			frame = getglobal(tostring(frame));
		end;
		if(scale == nil or not type(scale) == "number") then
			scale = 1.0;
		end;
		frame:SetWidth(tonumber(width) * scale);
		frame:SetHeight(tonumber(height) * scale);
	end;
end;

ikarus.ui.locked = false;

--  ATTENTION
--  Due to the missing stability of screen resolution calls ui lock will be disabled ??
function ikarus.ui:IsLocked()
	return self.locked;
end;

function ikarus.ui:SetLocked(locked)
	self.locked = locked;
end;


--[[
    ***********************************************************************
    Debug functions
    ***********************************************************************
]]

ikarus.debug.isEnabled = true;

function ikarus.debug:Dump(item)
	if(item == nil) then
		ikarus.utils:Print("nil object");
	else
		t = type(item);
		ikarus.utils:Print("["..t.."] "..tostring(item));
		if(t == "table") then
			for k,v in pairs(item) do
				ikarus.utils:Print("["..type(k).."] "..tostring(k).." ["..type(v).."] "..tostring(v));
			end;
		end;
	end;
end;

function ikarus.debug:DeepDump(item, offset)
	if(offset == nil) then
		offset = "";
	end;
	if(item == nil) then
		ikarus.utils:Print(offset.."nil object");
	else
		t = type(item);
		ikarus.utils:Print(offset.."["..t.."] "..tostring(item));
		if(t == "table") then
			for k,v in pairs(item) do
				if(type(v) == "table") then
				ikarus.utils:Print(offset.." -["..type(k).."] "..tostring(k)..":");
					self:DeepDump(v, offset.." ");
				else
					ikarus.utils:Print(offset.." -["..type(k).."] "..tostring(k).." ["..type(v).."] "..tostring(v));
				end;
			end;
		end;
	end;
end;

function ikarus.debug:IsEnabled()
    if(self.isEnabled)then
        return true;
    else
        return false;
    end;
end;

function ikarus.debug:SetEnabled(enabled)
	self.isEnabled = enabled;
end;

function ikarus.debug:Print(text, isError)
	if(self:IsEnabled()) then
	    ikarus.utils:Print(text, isError);
	end;
end;

--[[
    ***********************************************************************
    Constants
    ***********************************************************************
]]

ikarus.constants = {
    ["VERSION_NUMBER"] = "1.0.8",
    ["VERSION_SUFFIX"] = "",
    ["LOCATION"] = "DE",
    ["ADDON_DIR"] = "Interface/addons/ikarus/"
};

--  Lists anchor, parentanchor for alignments
ikarus.constants.alignments = {
	--  Alignment         | self             | parent
    ["TOP"] = { "BOTTOM", "TOP"},
    ["TOPLEFT"] = { "BOTTOMRIGHT", "TOPLEFT"},
    ["LEFT"] = { "RIGHT", "LEFT"},
    ["BOTTOMLEFT"] = { "TOPRIGHT", "BOTTOMLEFT"},
    ["BOTTOM"] = { "TOP", "BOTTOM"},
    ["BOTTOMRIGHT"] = { "TOPLEFT", "BOTTOMRIGHT"},
    ["RIGHT"] = { "LEFT", "RIGHT"},
    ["TOPRIGHT"] = { "BOTTOMLEFT", "TOPRIGHT"}
};

--  List of default wow colors used for health/mana/skillbar
ikarus.constants.colors = {
	--  Default colors used for wow-styles
	["WOW"] = {
		["GM"]          = { r = 1.00 , g = 1.00 , b = 1.00 },    
		[""]          	= { r = 1.00 , g = 0.96 , b = 0.41 }, -- housekeeper
		["WARRIOR"]     = { r = 0.78 , g = 0.61 , b = 0.43 },    
		["RANGER"]      = { r = 0.67 , g = 0.83 , b = 0.45 },
		["THIEF"]       = { r = 1.00 , g = 0.96 , b = 0.41 },  
		["MAGE"]        = { r = 0.41 , g = 0.80 , b = 0.94 },   
		["AUGUR"]       = { r = 1.00 , g = 1.00 , b = 1.00 },     	         
		["KNIGHT"]      = { r = 0.96 , g = 0.55 , b = 0.73 },        
		["WARDEN"]  	= { r = 0.77 , g = 0.12 , b = 0.23 },             
		["DRUID"]       = { r = 1.00 , g = 0.49 , b = 0.04 },  
		["MANATYPE1"] 	= { r = 0.30 , g = 0.50 , b = 0.85 },
		["MANATYPE2"] 	= { r = 1.00 , g = 0.00 , b = 0.00 },
		["MANATYPE3"] 	= { r = 0.55 , g = 0.95 , b = 0.00 },
		["MANATYPE4"] 	= { r = 0.95 , g = 0.95 , b = 0.00 }
	},
	
	--  Default mana type dependent colors
	["MANATYPE"] = {
		["MANATYPE1"] = { r = 0.30, g = 0.50, b = 0.85 },
		["MANATYPE2"] = { r = 1.00, g = 0.00, b = 0.00 },
		["MANATYPE3"] = { r = 0.55, g = 0.95, b = 0.00 },
		["MANATYPE4"] = { r = 0.95, g = 0.95, b = 0.00 }
	},
	
	--  Relation between player and unit
	["RELATION"] = {
		{ r = 1.00, g = 0.00, b = 0.00 },
		{ r = 1.00, g = 0.50, b = 0.00 },
		{ r = 1.00, g = 1.00, b = 0.00 },
		{ r = 0.00, g = 1.00, b = 0.00 },
		{ r = 0.00, g = 0.00, b = 1.00 } --Party
	},
	
	--  Default class colors
	["CLASS"] = {
		["GM"]          = { r = 1.000 , g = 1.000 , b = 1.000 }, 
		[""]          	= { r = 1.000 , g = 0.960 , b = 0.410 }, -- housekeeper   
		["WARRIOR"]     = { r = 0.984 , g = 0.255 , b = 0.024 },    
		["RANGER"]      = { r = 0.647 , g = 0.839 , b = 0.011 },
		["THIEF"]       = { r = 0.000 , g = 0.839 , b = 0.773 },  
		["MAGE"]        = { r = 0.988 , g = 0.447 , b = 0.067 },   
		["AUGUR"]       = { r = 0.157 , g = 0.549 , b = 0.925 },       	         
		["KNIGHT"]      = { r = 0.878 , g = 0.886 , b = 0.294 },        
		["WARDEN"]  	= { r = 1.000 , g = 1.000 , b = 1.000 },             
		["DRUID"]       = { r = 1.000 , g = 1.000 , b = 1.000 },  
	},
	
	--  Difficulty
	["DIFFICULTY"] = {
		{ r = 1.00, g = 0.00, b = 0.00 },
		{ r = 1.00, g = 1.00, b = 0.00 },
		{ r = 0.00, g = 0.77, b = 0.95 },
		{ r = 0.00, g = 1.00, b = 0.00 },
		{ r = 1.00, g = 1.00, b = 1.00 },
		{ r = 0.60, g = 0.60, b = 0.60 }
	}
};